
namespace UMC.Host;
using System;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using UMC.Net;

public class HttpsMimeSocket : HttpMime
{

    public override string Scheme => "https";

    public HttpsMimeSocket(System.IO.Stream stream, String ip)
    {
        this._stream = stream;
        this.ActiveTime = UMC.Data.Utility.TimeSpan();

        this.pid = stream.GetHashCode();

        this._Host = "127.0.0.1";

        this._remoteIpAddress = ip;

        HttpMimeServier.httpMimes.TryAdd(pid, this);
        Read();

    }
    Stream _stream;
    int pid = 0;

    public override int Id => pid;
    String _remoteIpAddress, _Host;
    public override String Host => _Host;
    public override String RemoteIpAddress => _remoteIpAddress;

    public override void Write(byte[] buffer, int offset, int count)
    {
        if (isDispose == false)
        {
            try
            {
                _stream.Write(buffer, offset, count);
            }
            catch
            {
                this.Dispose();
            }
        }
    }



    public override void OutputFinish()
    {
        try
        {

            this.ActiveTime = UMC.Data.Utility.TimeSpan();
            this.TimeOut = 20;
            request = null;
        }
        catch
        {
            this.Dispose();
        }
    }
    protected override void WebSocket(NetContext context)
    {
        if (context.Tag is NetHttpRequest)
        {
            var webr = context.Tag as NetHttpRequest;
            this.WebSocket(webr);
        }
    }
    bool isDispose = false;
    public override void Dispose()
    {

        if (isDispose == false)
        {
            isDispose = true;
            if (this._data != null)
            {
                System.Buffers.ArrayPool<byte>.Shared.Return(this._data);
                _data = null;
            }
            try
            {
                _stream.Close();
                _stream.Dispose();
                _webSocket?.Dispose();
            }
            catch
            {

            }
        }
        HttpMimeServier.httpMimes.TryRemove(pid, out var _);

    }
    async void WebSocket(NetHttpRequest webRequest)
    {
        try
        {
            var url = webRequest.Address;


            webRequest.Headers["Connection"] = "Upgrade";


            var client = new Socket(SocketType.Stream, ProtocolType.Tcp);

            await client.ConnectAsync(await NetProxy.DNS(url.Host), url.Port);

            if (url.Scheme == "https")
            {
                SslStream ssl = new SslStream(new NetworkStream(client, true), false, (sender, certificate, chain, sslPolicyErrors) => true);
                await ssl.AuthenticateAsClientAsync(url.Host, null, SslProtocols.None, false);

                await ssl.WriteAsync(_data, 0, UMC.Net.NetHttpResponse.Header(webRequest, _data));
                int size = await ssl.ReadAsync(_data, 0, _data.Length);

                if (NetBridge.ResponseHeader(_data, 0, size, new NameValueCollection(), out var statucode) && statucode == HttpStatusCode.SwitchingProtocols)
                {
                    request = _webSocket = new HttpsWebSocket(this, ssl);

                    this._stream.Write(_data, 0, size);
                }
                else
                {
                    this._stream.Write(_data, 0, size);
                    this.Dispose();
                }
            }
            else
            {
                client.Send(_data, 0, UMC.Net.NetHttpResponse.Header(webRequest, _data), SocketFlags.None);
                var size = client.Receive(_data, 0, _data.Length, SocketFlags.None);
                if (NetBridge.ResponseHeader(_data, 0, size, new NameValueCollection(), out var statucode) && statucode == HttpStatusCode.SwitchingProtocols)
                {
                    request = _webSocket = new HttpWebSocket(this, client);
                    this._stream.Write(_data, 0, size);
                }
                else
                {

                    this._stream.Write(_data, 0, size);
                    this.Dispose();
                }

            }

            HttpMimeServier.httpMimes.TryRemove(this.pid, out var _);

        }
        catch (Exception ex)
        {
            OutText(500, ex.ToString());
        }
    }


    WebSocket _webSocket;
    byte[] _data = System.Buffers.ArrayPool<byte>.Shared.Rent(0x600);

    MimeRequest request;

    async void Read()
    {
        int size = 0;
        try
        {
            while ((size = await _stream.ReadAsync(this._data, 0, this._data.Length)) > 0)
            {
                this.ActiveTime = UMC.Data.Utility.TimeSpan();
                if (request == null)
                {
                    request = new HttpMimeRequest(this);
                }
                var req = request;
                req.Receive(this._data, 0, size);

                if (req.IsHttpFormatError)
                {
                    break;
                }

            }
        }
        catch
        {
            this.Dispose();
            return;
        }
        this.Dispose();

    }

}
